/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.repository;

import cz.mzk.oai.metadataRepository.tools.CannotReadDirectoryException;
import cz.mzk.oai.metadataRepository.MetadataValidator;
import cz.mzk.oai.metadataRepository.repository.RecordAnalyzer.BeforeAfterDecision;
import cz.mzk.oai.metadataRepository.Tools;
import cz.mzk.oai.metadataRepository.metadata.DateStamp;
import cz.mzk.oai.metadataRepository.metadata.MarcRecord;
import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.metadata.OaiSet;
import cz.mzk.oai.metadataRepository.tools.FileTools;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;

/**
 * @author Martin Rehanek, Martin.Rehanek@gmail.com
 * The repository cannot detect that there has been some change
 * in collections if this change is performad by something external.
 * For example if you run fileHarvester than you must restart web application in order for it
 * to realize the changes
 *
 */
public class Repository {

    //private Map<String, MetadataCollection> collectionMap;
    private List<MetadataCollection> collections = new ArrayList<MetadataCollection>();
    private File rootDir;
    //private static String DEFAULT_MARC_2_ESE_TEMPL = "/tmp/MARC2ESE.xsl";
    private RecordAnalyzer analyzer;
    // private Set<OaiSet> sets;
    //mzk03
    private MetadataCollection mollMapsBefore1800;
    private MetadataCollection mollMapsAfter1800;
    private MetadataCollection mollMapsError1800;
    private MetadataCollection schramVeduteBefore1800;
    private MetadataCollection schramVeduteAfter1800;
    private MetadataCollection schramVeduteError1800;
    private MetadataCollection schramPortraitsBefore1800;
    private MetadataCollection schramPortraitsAfter1800;
    private MetadataCollection schramPortraitsError1800;
    private MetadataCollection manuscriptsBefore1800;
    private MetadataCollection manuscriptsAfter1800;
    private MetadataCollection manuscriptsError1800;
    private MetadataCollection generalMzk03Before1800;
    private MetadataCollection generalMzk03After1800;
    private MetadataCollection generalMzk03Error1800;
    private MetadataCollection oldMapsBefore1800;
    private MetadataCollection oldMapsAfter1800;
    private MetadataCollection oldMapsError1800;
    //mzk01
    private MetadataCollection generalMzk01Before1800;
    private MetadataCollection generalMzk01After1800;
    private MetadataCollection generalMzk01Error1800;
    private String marc2dcXslt;
    private static Map<String, Repository> instances;
    private Properties properties;
    private Handler logHandler;
    private String logFile;

    public static Repository instanceOf(Properties properties/*String rootDir, String marc2eseXslt, String marc2dcXslt*/) {
        try {
            String rootDir = properties.getProperty("Repository.rootDir");
            if (instances == null) {
                instances = new HashMap<String, Repository>();
                Repository instance = new Repository(properties);
                instances.put(rootDir, instance);
                return instance;
            } else {
                Repository oldInstance = instances.get(rootDir);
                if (oldInstance == null) {
                    Repository newInstance = new Repository(properties);
                    instances.put(rootDir, newInstance);
                    return newInstance;
                } else {
                    return oldInstance;
                }
            }
        } catch (SecurityException ex) {
            Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        } catch (IOException ex) {
            Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     *@param properties properties containing Repository.rootDir and Repository.xslt.marc2dc
     *@throws IOException if failed to initialize log file
     *@throws SecurityException if failed to initialize log file
     */
    private Repository(Properties properties) throws SecurityException, IOException {
        this.properties = properties;
        String rootDirectory = properties.getProperty("repositoryManager.Repository.rootDir");
        File rootDirFile = new File(rootDirectory);
        marc2dcXslt = properties.getProperty("repositoryManager.xslt.marc2dc");
        if (!rootDirFile.exists()) {
            rootDirFile.mkdir();
            Logger.getLogger(Repository.class.getName()).log(Level.INFO, rootDir + " does not exist, creating");
        } else if (!rootDirFile.isDirectory()) {
            throw new IllegalArgumentException(rootDir + " is not directory");
        }
        this.logFile = rootDirectory + File.separatorChar + "repository.log";
        Logger logger = Logger.getLogger(Repository.class.getName());
        logHandler = new FileHandler(logFile, true);
        logHandler.setFormatter(new SimpleFormatter());
        logger.addHandler(logHandler);
        this.rootDir = rootDirFile;
        analyzer = new RecordAnalyzer();
        initCollections(true);
    }

    private void initCollections(boolean createSets) {
        MetadataBase mzk03 = MetadataBase.MZK03;

        //Moll maps
        String marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.mollMaps");
        mollMapsBefore1800 = addNewCollection(mzk03, "mollMapsBefore1800", marc2eseXslt, marc2dcXslt);
        mollMapsAfter1800 = addNewCollection(mzk03, "mollMapsAfter1800", marc2eseXslt, marc2dcXslt);
        mollMapsError1800 = addNewCollection(mzk03, "mollMapsError1800", marc2eseXslt, marc2dcXslt);

        //Schram vedute
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.schramVedute");
        schramVeduteBefore1800 = addNewCollection(mzk03, "schramVeduteBefore1800", marc2eseXslt, marc2dcXslt);
        schramVeduteAfter1800 = addNewCollection(mzk03, "schramVeduteAfter1800", marc2eseXslt, marc2dcXslt);
        schramVeduteError1800 = addNewCollection(mzk03, "schramVeduteError1800", marc2eseXslt, marc2dcXslt);

        //Schram portraits
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.schramPortraits");
        schramPortraitsBefore1800 = addNewCollection(mzk03, "schramPortraitsBefore1800", marc2eseXslt, marc2dcXslt);
        schramPortraitsAfter1800 = addNewCollection(mzk03, "schramPortraitsAfter1800", marc2eseXslt, marc2dcXslt);
        schramPortraitsError1800 = addNewCollection(mzk03, "schramPortraitsError1800", marc2eseXslt, marc2dcXslt);

        //manuscripts
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.mzk03");
        manuscriptsBefore1800 = addNewCollection(mzk03, "manuscriptsBefore1800", marc2eseXslt, marc2dcXslt);
        manuscriptsAfter1800 = addNewCollection(mzk03, "manuscriptsAfter1800", marc2eseXslt, marc2dcXslt);
        manuscriptsError1800 = addNewCollection(mzk03, "manuscriptsError1800", marc2eseXslt, marc2dcXslt);

        //oldMaps
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.mzk03");
        oldMapsBefore1800 = addNewCollection(mzk03, "oldMapsBefore1800", marc2eseXslt, marc2dcXslt);
        oldMapsAfter1800 = addNewCollection(mzk03, "oldMapsAfter1800", marc2eseXslt, marc2dcXslt);
        oldMapsError1800 = addNewCollection(mzk03, "oldMapsError1800", marc2eseXslt, marc2dcXslt);

        //mzk03 other
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.mzk03");
        generalMzk03Before1800 = addNewCollection(mzk03, "generalMzk03Before1800", marc2eseXslt, marc2dcXslt);
        generalMzk03After1800 = addNewCollection(mzk03, "generalMzk03After1800", marc2eseXslt, marc2dcXslt);
        generalMzk03Error1800 = addNewCollection(mzk03, "generalMzk03Error1800", marc2eseXslt, marc2dcXslt);

        //mzk01
        MetadataBase mzk01 = MetadataBase.MZK01;
        marc2eseXslt = properties.getProperty("repositoryManager.xslt.marc2ese.mzk01");
        generalMzk01Before1800 = addNewCollection(mzk01, "generalMzk01Before1800", marc2eseXslt, marc2dcXslt);
        generalMzk01After1800 = addNewCollection(mzk01, "generalMzk01After1800", marc2eseXslt, marc2dcXslt);
        generalMzk01Error1800 = addNewCollection(mzk01, "generalMzk01Error1800", marc2eseXslt, marc2dcXslt);


        if (createSets) {
            //collection sets

            //mollMaps
            String mollMapsSet = "mollMaps-collection";
            mollMapsBefore1800.addToSet(mollMapsSet);
            mollMapsAfter1800.addToSet(mollMapsSet);
            mollMapsError1800.addToSet(mollMapsSet);

            //schramVedute
            String schramVeduteSet = "schramVedute-collection";
            schramVeduteBefore1800.addToSet(schramVeduteSet);
            schramVeduteAfter1800.addToSet(schramVeduteSet);
            schramVeduteError1800.addToSet(schramVeduteSet);

            //schramPortraits
            String schramPortraitsSet = "schramPortraits-collection";
            schramPortraitsBefore1800.addToSet(schramPortraitsSet);
            schramPortraitsAfter1800.addToSet(schramPortraitsSet);
            schramPortraitsError1800.addToSet(schramPortraitsSet);

            //manuscripts
            String manuscriptsSet = "manuscripts-collection";
            manuscriptsBefore1800.addToSet(manuscriptsSet);
            manuscriptsAfter1800.addToSet(manuscriptsSet);
            manuscriptsError1800.addToSet(manuscriptsSet);

            String oldMapsSet = "oldMaps-collection";
            oldMapsBefore1800.addToSet(oldMapsSet);
            oldMapsAfter1800.addToSet(oldMapsSet);
            oldMapsError1800.addToSet(oldMapsSet);

            //rest of the mzk03
            String mzk03Only = "mzk03-other";
            generalMzk03Before1800.addToSet(mzk03Only);
            generalMzk03After1800.addToSet(mzk03Only);
            generalMzk03Error1800.addToSet(mzk03Only);

            //the whole mzk01
            String mzk01Set = "mzk01-other";
            generalMzk01Before1800.addToSet(mzk01Set);
            generalMzk01After1800.addToSet(mzk01Set);
            generalMzk01Error1800.addToSet(mzk01Set);

            //sets composed of several collections

            //maps
            String mapsSet = "maps";
            mollMapsBefore1800.addToSet(mapsSet);
            mollMapsAfter1800.addToSet(mapsSet);
            mollMapsError1800.addToSet(mapsSet);
            oldMapsBefore1800.addToSet(mapsSet);
            oldMapsAfter1800.addToSet(mapsSet);
            oldMapsError1800.addToSet(mapsSet);

            //manuscriptorium
            String mnsSet = "manuscriptorium";
            mollMapsBefore1800.addToSet(mnsSet);
            schramVeduteBefore1800.addToSet(mnsSet);
            schramPortraitsBefore1800.addToSet(mnsSet);
            manuscriptsBefore1800.addToSet(mnsSet);
            oldMapsBefore1800.addToSet(mnsSet);
            generalMzk03Before1800.addToSet(mnsSet);
            generalMzk01Before1800.addToSet(mnsSet);

            //europeana local
            String euLocalSet = "europeanaLocal";
            schramPortraitsBefore1800.addToSet(euLocalSet);
            schramPortraitsAfter1800.addToSet(euLocalSet);
            schramPortraitsError1800.addToSet(euLocalSet);

            //europeana travel
            String euTravelSet = "europeanaTravel";
            mollMapsBefore1800.addToSet(euTravelSet);
            mollMapsAfter1800.addToSet(euTravelSet);
            mollMapsError1800.addToSet(euTravelSet);
            schramVeduteBefore1800.addToSet(euTravelSet);
            schramVeduteAfter1800.addToSet(euTravelSet);
            schramVeduteError1800.addToSet(euTravelSet);
            //TODO: add oldMaps when they're digitalized and picture available 

        }
    }

    public MetadataCollection getCollection(String name) {
        for (MetadataCollection col : collections) {
            if (name.equals(col.getName())) {
                return col;
            }
        }
        return null;
    }

    /**
     *
     * @return list of all collections
     */
    public List<MetadataCollection> getCollections() {
        return collections;//Collections.unmodifiableList(collections);
    }

    /**
     *
     * @param base for instance MZK01, MZK03
     * @return list of all collection from particular base
     */
    public List<MetadataCollection> getCollections(MetadataBase base) {
        List<MetadataCollection> result = new ArrayList<MetadataCollection>();
        for (MetadataCollection col : collections) {
            if (col.getBase() == base) {
                result.add(col);
            }
        }
        return result;
    }

    /**
     *
     * @return
     */
    public Set<OaiSet> getSets() {
        Set<OaiSet> sets = new HashSet<OaiSet>();
        for (MetadataCollection col : collections) {
            for (String set : col.getSets()) {
                OaiSet newSet = new OaiSet(set, set, col.size());
                OaiSet oldSet = getOaiSet(sets, newSet.getSetSpec());
                if (oldSet == null) {
                    sets.add(newSet);
                } else {
                    oldSet.setSize(oldSet.getSize() + newSet.getSize());
                }
            }
        }
        return sets;

    }

    private OaiSet getOaiSet(Set<OaiSet> set, String setSpec) {
        for (OaiSet oaiSet : set) {
            if (setSpec.equals(oaiSet.getSetSpec())) {
                return oaiSet;
            }
        }
        return null;
    }

//    /**
//     * This should probably belong to view (project oaicat)
//     * @return
//     */
//    public List<String> getSetsXmls() {
//        List<String> setXmls = new ArrayList<String>();
//        Set<OaiSet> sets = getSets();
//        for (OaiSet set : sets) {
//            Document document = DocumentHelper.createDocument();
//            Element setEl = document.addElement("set");
//            Element setSpec = setEl.addElement("setSpec");
//            setSpec.addText(set.getSetSpec());
//            Element setName = setEl.addElement("setName");
//            setName.addText(set.getSetName());
//            Element setDesc = setEl.addElement("setDescription");
//            Namespace oai_dc = new Namespace(MetadataFormat.oai_dc.name(), MetadataFormat.oai_dc.getNamespace());
//            Namespace xsi = new Namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
//            Namespace dc = new Namespace("dc", "http://purl.org/dc/elements/1.1/");
//            Element dcEl = setDesc.addElement(new QName("dc", oai_dc));
//            DocumentFactory factory = DocumentFactory.getInstance();
//            Attribute schemaLocation = factory.createAttribute(dcEl, new QName("schemaLocation", xsi), "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
//            dcEl.add(schemaLocation);
//            Element dcDescEl = dcEl.addElement(new QName("description", dc));
//            dcDescEl.addText("This set contains " + set.getSize() + " items");
//            setXmls.add(document.getRootElement().asXML());
//            //System.out.println("node: " + document.getRootElement().asXML());
//        }
//        return setXmls;
//    }
    private MetadataCollection addNewCollection(MetadataBase base, String collectionName, String marc2eseTempl, String marc2dcTempl) {
        String collectionRootDir = FileTools.buildSubdirPath(rootDir.getAbsolutePath(), collectionName);
        MetadataCollection collection = new MetadataCollection(base, collectionName, collectionRootDir, marc2eseTempl, marc2dcTempl, true, true, true);
        //TODO: vyhodit vyjimku, pokud kolekce jiz existuje
        collections.add(collection);
        return collection;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Collections in '");
        builder.append(rootDir);
        builder.append("':\n\n");
        int inMarc = 0;
        int inEse = 0;
        int inDc = 0;
        int itemCounter = 0;
        for (MetadataCollection col : collections) {
            builder.append(col.toString());
            itemCounter += col.size();
            inMarc += col.records("marc21");
            inEse += col.records("ese");
            inDc += col.records("oai_dc");
        }
        builder.append("All items: " + itemCounter);
        builder.append('\n');
        builder.append("marc21: " + inMarc);
        builder.append('\n');
        builder.append("ese: " + inEse);
        builder.append('\n');
        builder.append("oai_dc: " + inDc);
        return builder.toString();
    }

    /**
     *
     * @param marcDoc
     * @param id
     * @param datestamp
     * @param thorough
     * @return true if suitable collection found and item was actually added (or replaced)
     */
    public boolean addToCollection(MetadataBase base, Document marcDoc, String id, DateStamp datestamp, boolean thorough, boolean debug) {
        MarcRecord marcRecord = new MarcRecord(marcDoc, id);
        MetadataCollection collection = chooseCollection(marcRecord, base);
        boolean hasPreview = marcRecord.hasPreview();
        if (collection != null) {
            if (debug) {
                System.out.println("chosen collection " + collection.getName());
            }
            boolean added = collection.addItem(marcDoc, marcRecord.getId(), datestamp, hasPreview, true, debug);
            if (thorough) {
                //search all other collections for the item and remove if found
                for (MetadataCollection coll : collections) {
                    if (!collection.getName().equals(coll.getName())
                            && (collection.getBase() == coll.getBase())) {
                        coll.removeItem(marcRecord.getId());
                    }
                }
            }
            return added;
        } else {
            return false;
        }
    }

    private MetadataCollection chooseCollection(MarcRecord record, MetadataBase base) {
        BeforeAfterDecision decision = analyzer.decide1800(record);

        if (base == MetadataBase.MZK03) {
            //moll
            if (analyzer.isMollMap(record)) {
                switch (decision) {
                    case BEFORE:
                        return this.mollMapsBefore1800;
                    case AFTER:
                        return this.mollMapsAfter1800;
                    case ERROR:
                        return this.mollMapsError1800;
                }
            }

            //schram
            boolean isSchramPortrait = analyzer.isSchramPortrait(record);
            boolean isSchramVeduta = analyzer.isSchramVedutaOrMap(record);
            if (isSchramPortrait && isSchramVeduta) {
                String message = "evaluated as both schramVeduta and schramPortrait. ID:" + record.getId();
                Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, message);
                return null;
            } else if (isSchramPortrait) {
                switch (decision) {
                    case BEFORE:
                        return this.schramPortraitsBefore1800;
                    case AFTER:
                        return this.schramPortraitsAfter1800;
                    case ERROR:
                        return this.schramPortraitsError1800;
                }
            } else if (isSchramVeduta) {
                switch (decision) {
                    case BEFORE:
                        return schramVeduteBefore1800;
                    case AFTER:
                        return schramVeduteAfter1800;
                    case ERROR:
                        return schramVeduteError1800;
                }
            }

            //manucripts
            boolean isManuscript = analyzer.isManuscript(record);
            if (isManuscript) {
                switch (decision) {
                    case BEFORE:
                        return manuscriptsBefore1800;
                    case AFTER:
                        return manuscriptsAfter1800;
                    case ERROR:
                        return manuscriptsError1800;
                }
            }

            //oldMaps
            boolean isOldMap = analyzer.isOldMap(record);
            if (isOldMap) {
                switch (decision) {
                    case BEFORE:
                        return oldMapsBefore1800;
                    case AFTER:
                        return oldMapsAfter1800;
                    case ERROR:
                        return oldMapsError1800;
                }
            }

            //if no collection chosen, we use default one
            switch (decision) {
                case BEFORE:
                    return this.generalMzk03Before1800;
                case AFTER:
                    return this.generalMzk03After1800;
                case ERROR:
                    return this.generalMzk03Error1800;
            }

        } else if (base == MetadataBase.MZK01) {
            //no collections yet, just whole base in single collection
            switch (decision) {
                case BEFORE:
                    return this.generalMzk01Before1800;
                case AFTER:
                    return this.generalMzk01After1800;
                case ERROR:
                    return this.generalMzk01Error1800;
            }
        }

        return null;
    }

    /*
     * Returns list of collections that are in set or all collection if setSpec is null or empty string
     */
    public List<MetadataCollection> getCollections(String setSpec) {
        if (setSpec == null || setSpec.equals("") || setSpec.equals("null")) {
            //pozor na to, nekdy to vraci i string "null"
            //System.err.println("getCollections: setSpec = null");
            //System.err.println("collections: " + collections);
            return collections;
        }
        List<MetadataCollection> selectedCollections = new ArrayList<MetadataCollection>();
        for (MetadataCollection col : collections) {
            if (col.getSets().contains(setSpec)) {
                selectedCollections.add(col);
            }
        }
        return selectedCollections;
    }

    public void close() {
        for (MetadataCollection col : collections) {
            col.close();
        }
        Repository.instances.remove(this.rootDir.getAbsolutePath());
    }

    /**
     * @param id of an item
     * @param metadataFormat
     * @return record in xml
     * @throws NoSuchRecordException if item with this id has no record in requested metadataFormat
     */
    public Document getRecord(String id, MetadataFormat format, boolean validate) throws NoSuchRecordException {
        for (MetadataCollection col : collections) {
            if (col.contains(id)) {
                //System.out.println("found in collection " + col.getName());
                return col.getRecord(id, format, validate);
            }
        }
        throw new NoSuchRecordException();//not present in any collection
    }

    public Item getItem(String id) {
        for (MetadataCollection col : collections) {
            Item item = col.getItem(id);
            if (item != null) {
                //System.out.println("found in " + col.getName());
                return item;
            }
        }
        return null;

    }

    public void printSets() {
        System.out.println("Repository.printSets(): Not implemented yet");
    }

    private String setToString(String setSpec) {
        StringBuilder builder = new StringBuilder();
        builder.append(setSpec);
        builder.append(':');
        int counter = 0;
        for (MetadataCollection col : collections) {
            if (col.getSets().contains(setSpec)) {
                counter += col.size();
            }
        }
        builder.append(counter);
        builder.append('\n');
        return builder.toString();
    }

    /**
     * Removes all data from repository and creates emty repository directory
     */
    public boolean clear() {
        try {
            String command = null;
            if ("Windows 7".equals(System.getProperty("os.name"))) {
                command = "rmdir -rf " + rootDir.getAbsolutePath();
            } else {
                command = "rm -rf " + rootDir.getAbsolutePath();
            }
            Process p = Runtime.getRuntime().exec(command);
            p.waitFor();
            if (p.exitValue() != 0) {
                StringBuilder builder = new StringBuilder();
                builder.append("Could not remove " + rootDir + '\n');
                builder.append("Error in '");
                builder.append(command);
                builder.append("':");
                builder.append(Tools.errorstreamToString(p));
                Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, builder.toString());
                return false;
            } else {
                command = "mkdir " + rootDir.getAbsolutePath();
                p = Runtime.getRuntime().exec(command);
                p.waitFor();
                if (p.exitValue() != 0) {
                    StringBuilder builder = new StringBuilder();
                    builder.append("Could not clear and init " + rootDir + '\n');
                    builder.append("Error in '");
                    builder.append(command);
                    builder.append("':");
                    builder.append(Tools.errorstreamToString(p));
                    Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, builder.toString());
                    return false;
                }
            }
            return true;
        } catch (InterruptedException ex) {
            Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        } catch (IOException ex) {
            Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
    }

    /**
     * This method removes all metadata files in secondary formats and
     * recreates them. It should be used when all XSLTs are changed
     * @param ese if true all ese records will be recreated
     * @param dc if true all oai_dc records will be recreated
     */
    public void recreateRecords(boolean ese, boolean dc) {
        for (MetadataCollection col : collections) {
            col.recreateRecords(ese, dc);
        }
    }

    /**
     * This method removes metadata files in secondary formats of specified collection
     * and recreates them. It should be used when particular XSLT is changed
     * @param collectionName name of collection to be updated
     * @param ese if true ese records will be recreated
     * @param dc if true oai_dc records will be recreated
     */
    public void recreateRecords(String collectionName, boolean ese, boolean dc) {
        if (collectionName == null) {
            throw new NullPointerException("collectionName");
        }
        MetadataCollection collection = null;
        for (MetadataCollection col : collections) {
            if (collectionName.equals(col.getName())) {
                collection = col;
                break;
            }
        }
        if (collection == null) {
            Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, "No such a collection '" + collectionName + "'");
        } else {
            collection.recreateRecords(ese, dc);
        }
    }

    public void updateProperties() {
        for (MetadataCollection col : collections) {
            col.updateProperties();
        }
    }

    /**
     * Iterates through all collections and prints number of invalid files in format
     * @param format
     */
    public void validateMetadata(MetadataFormat format) {
        int total = 0;
        int notValid = 0;
        int[] result;
        for (MetadataCollection col : collections) {

            if (col.supportsFormat(format) //&& col.getName().equals("mollMapsAfter1800")
                    ) {
                System.out.println("kolekce: " + col.getName());
                File dir = new File(col.getRootDir() + File.separator + format.getDirName());
                try {
                    result = MetadataValidator.instanceOf().validateDir(dir, format, false);
                    total += result[0];
                    notValid += result[1];
                } catch (CannotReadDirectoryException ex) {
                    Logger.getLogger(Repository.class.getName()).log(Level.SEVERE, ex.getMessage());
                }
                System.out.println("------------------------------");
            }
        }
        System.out.println("total: " + total);
        System.out.println("not valid: " + notValid);
    }
}
